/*
 #
 #  Files       : MatrixBase.h
 #                ( C++ header file )
 #
 #  Description : The SmallMatrix Library
 #                ( http://code.google.com/p/smallmatrix )
 #
 #  Copyright   : Olivier Juan
 #                ( http://www.mas.ecp.fr/vision/Personnel/juan/ )
 #
 #  License     : CeCILL-C
 #                ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
 #
 #  This software is governed by the CeCILL-C license under French law and
 #  abiding by the rules of distribution of free software.  You can  use,
 #  modify and or redistribute the software under the terms of the CeCILL-C
 #  license as circulated by CEA, CNRS and INRIA at the following URL
 #  "http://www.cecill.info".
 #
 #  As a counterpart to the access to the source code and  rights to copy,
 #  modify and redistribute granted by the license, users are provided only
 #  with a limited warranty  and the software's author,  the holder of the
 #  economic rights,  and the successive licensors  have only  limited
 #  liability.
 #
 #  In this respect, the user's attention is drawn to the risks associated
 #  with loading,  using,  modifying and/or developing or reproducing the
 #  software by the user in light of its specific status of free software,
 #  that may mean  that it is complicated to manipulate,  and  that  also
 #  therefore means  that it is reserved for developers  and  experienced
 #  professionals having in-depth computer knowledge. Users are therefore
 #  encouraged to load and test the software's suitability as regards their
 #  requirements in conditions enabling the security of their systems and/or
 #  data to be ensured and,  more generally, to use and operate it in the
 #  same conditions as regards security.
 #
 #  The fact that you are presently reading this means that you have had
 #  knowledge of the CeCILL-C license and that you accept its terms.
 #
*/

#ifndef _SMALLMATRIX_MATRIX_BASE_H
#define _SMALLMATRIX_MATRIX_BASE_H

#include <SmallMatrix/SmallMatrix.h>

NAMESPACE_BEGIN(SmallMatrix)

template <typename T> class Matrix_Base
{
public:
	typedef T self;
	typedef T result_type;
	typedef DescriptionTraits<T> Descriptor;
	typedef typename Descriptor::value_type value_type;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;

	enum { SIZE = typename Descriptor::SIZE };
	enum { ROW = typename Descriptor::ROW };
	enum { COL = typename Descriptor::COL };
	enum { SYM = typename Descriptor::SYM };

public:
	value_type _data[SIZE];
	//! Template Accessor
	template <int Idx>
		reference dataAccess() {
			STATIC_ASSERT(Idx>=0);
			STATIC_ASSERT(Idx<SIZE);
			return _data[Idx];
		}
	//! Read-Only Template Accessor
	template <int Idx>
		const_reference dataAccess() const {
			STATIC_ASSERT(Idx>=0);
			STATIC_ASSERT(Idx<SIZE);
			return _data[Idx];
		}
	template <int IdxR, int IdxC>
		reference Access() {
			return Child().template Access<IdxR, IdxC>();
		}
	//! Read-Only Template Accessor
	template <int IdxR, int IdxC>
		const_reference Access() const {
			return Child().template Access<IdxR, IdxC>();
		}
public:
	//! Child Caster
	typename Matrix_Base<T>::self& Child() {return *reinterpret_cast<T*>(this);}
	//! Read-Only Child Caster
	const typename Matrix_Base<T>::self& Child() const {return *reinterpret_cast<const T*>(this);}
public:
	//! Null Constructor
	INLINE Matrix_Base() {
		//typedef Expressions<Assign,T, reel > _myExpression;
		//STATIC_ASSERT(_myExpression::OK);
		//_myExpression _myExpr(Child(), 0);
		//Action<_myExpression>::act(_myExpr);
	}
	//! Set Constructor
	//INLINE Matrix_Base(const reel &v) {
	//	typedef Expressions<Assign,T, reel > _myExpression;
	//	STATIC_ASSERT(_myExpression::OK);
	//	_myExpression _myExpr(Child(), v);
	//	Action<_myExpression>::act(_myExpr);
	//}
	//! Tabular Constructor
	INLINE Matrix_Base(const reel tab[SIZE]) {
		//Matrix_Base<T>& ref = *this;
		//for (int i=0;i<SIZE;i++)
		//	ref[i]=tab[i];
	}
	//! Convert Constructor
	template <typename TT> INLINE Matrix_Base(const TT& copy) {
		//typedef Expressions<Assign,T, TT > _myExpression;
		//STATIC_ASSERT(_myExpression::OK);
		//_myExpression _myExpr(Child(), copy);
		//Action<_myExpression>::act(_myExpr);
	}
	//! Copy Constructor
	INLINE Matrix_Base(const Matrix_Base<T>& copy) {
		//typedef Expressions<Assign,T, T > _myExpression;
		//STATIC_ASSERT(_myExpression::OK);
		//_myExpression _myExpr(Child(), copy.Child());
		//Action<_myExpression>::act(_myExpr);
	}
	//! Matrix-Matrix Affectation
	//template <typename TT> INLINE typename Matrix_Base<T>::self& operator=(const TT& Expr) {
	//	typename Matrix_Base<T>::self& ref=Child();
	//	typedef Expressions<Assign,T,TT> _myExpression;
	//	STATIC_ASSERT(_myExpression::OK);
	//	_myExpression _myExpr(ref,Expr);
	//	Action<_myExpression>::act(_myExpr);
	//	return ref;
	//}
	//INLINE typename Matrix_Base<T>::self& operator=(const Matrix_Base<T>& copy) {
	//	typename Matrix_Base<T>::self& ref=Child();
	//	typedef Expressions<Assign,T,T> _myExpression;
	//	STATIC_ASSERT(_myExpression::OK);
	//	_myExpression _myExpr(ref, copy.Child());
	//	Action<_myExpression>::act(_myExpr);
	//	return ref;
	//}
	//INLINE int rows() const { return ROW; }
	//INLINE int cols() const { return COL; }
	//INLINE Expressions<UnaryMinus,T,void> operator-()const;
	//INLINE Expressions<Mult, T, reel > operator*(const reel& alpha)const;
	//INLINE Expressions<Mult, T, reel > operator/(const reel& alpha)const;
	//INLINE typename Matrix_Base<T>::self& operator*=(const reel& alpha);
	//INLINE typename Matrix_Base<T>::self& operator/=(const reel& alpha);
	//INLINE Expressions<Add, T, reel > operator+(const reel& alpha)const;
	//INLINE Expressions<Substract, T, reel > operator-(const reel& alpha)const;
	//INLINE typename Matrix_Base<T>::self& operator+=(const reel& alpha);
	//INLINE typename Matrix_Base<T>::self& operator-=(const reel& alpha);
	INLINE reference operator[](const int& idx)
	{
		assert((idx>=0)&&(idx<SIZE));
		return _data[idx];
	}
	INLINE const_reference operator[](const int& idx) const
	{
		assert((idx>=0)&&(idx<SIZE));
		return _data[idx];
	}
	//INLINE reel& operator()(const int& idxm,const int& idxn);
	//INLINE const reel& operator()(const int& idxm,const int& idxn)const;
	//INLINE typename Matrix_Base<T>::self& set(const reel& value);
	//INLINE reel norm()const;
	//INLINE reel norm2()const;
	//INLINE reel normL1()const;
	//INLINE reel normLinf()const;
	//INLINE reel normL2()const;
	//template <typename TT> INLINE reel dot(const Matrix_Base<TT>& Two)const;
	//template <typename TT> INLINE typename Matrix_Product_Scheme_Trait< T, TT >::result_type operator*(const Matrix_Base<TT>& M1) const;
	//template <typename TT> INLINE typename Matrix_Base<T>::self& mult(const TT& Two);
	//template <typename TT> INLINE typename Matrix_Base<T>::self& div(const TT& Two);
	//INLINE typename Matrix_Base<T>::self& sqrt();
	//template <typename TT> INLINE bool operator==(const Matrix_Base<TT>& Two) const;
	//template <typename TT> INLINE Expressions<Add, T, TT> operator+(const TT& Two) const;
	//template <typename TT> INLINE Expressions<Substract, T, TT> operator-(const TT& Two) const;
	////template <typename TT> INLINE typename Matrix_Base<T>::self& operator+=(const Matrix_Base<TT>& Two);
	////template <typename TT> INLINE typename Matrix_Base<T>::self& operator-=(const Matrix_Base<TT>& Two);
	//template <typename TT> INLINE typename Matrix_Base<T>::self& operator+=(const TT& Expr);
	//template <typename TT> INLINE typename Matrix_Base<T>::self& operator-=(const TT& Expr);
	//INLINE void write(std::ostream& f) const;
	//INLINE void read(std::istream& f);
};
//! Matrix Negative
//template <typename T> INLINE Expressions<UnaryMinus,T,void> Matrix_Base<T>::operator-()const
//{
//	typedef Expressions<UnaryMinus,T,void> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	const typename Matrix_Base<T>::self& ref=Child();
//	return _myExpression(ref);
//	//typename Matrix_Base<T>::self temp(Child());
//	//operation_Unrolled<T::ROW>::Operation<T,reel,Op_Prod>::compute(temp,-1);
//	//return temp;
//}
////! Matrix-Scalar Product
//template <typename T> INLINE Expressions<Mult, T, reel > Matrix_Base<T>::operator*(const reel& alpha)const
//{
//	typedef Expressions<Mult,T,reel> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename const Matrix_Base<T>::self& ref=Child();
//	return _myExpression(ref,alpha);
//}
////! Matrix-Scalar Quotient
//template <typename T> INLINE Expressions<Mult, T, reel > Matrix_Base<T>::operator/(const reel& alpha)const
//{
//	typedef Expressions<Mult,T,reel> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	assert(alpha!=0);
//	typename const Matrix_Base<T>::self& ref=Child();
//	return _myExpression(ref,reel(1)/alpha);
//}
////! Matrix-Scalar Product to
//template <typename T> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator*=(const reel& alpha)
//{
//	typedef Expressions<MultAssign, T, reel > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child();
//	_myExpression _myExpr(ref, alpha);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Matrix-Scalar Quotient to
//template <typename T> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator/=(const reel& alpha)
//{
//	assert(alpha!=0);
//	typedef Expressions<MultAssign, T, reel > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child();
//	_myExpression _myExpr(ref, reel(1)/alpha);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Matrix-Scalar Add
//template <typename T> INLINE Expressions<Add, T, reel > Matrix_Base<T>::operator+(const reel& alpha)const
//{
//	typedef Expressions<Add, T, reel > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename const Matrix_Base<T>::self& ref=Child();
//	return _myExpression(ref, alpha);
//}
////! Matrix-Scalar Substract
//template <typename T> INLINE Expressions<Substract, T, reel > Matrix_Base<T>::operator-(const reel& alpha)const
//{
//	typedef Expressions<Substract, T, reel > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename const Matrix_Base<T>::self& ref=Child();
//	return _myExpression(ref, alpha);
//}
////! Matrix-Scalar Add to
//template <typename T> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator+=(const reel& alpha)
//{
//	typedef Expressions<AddAssign, T, reel > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child();
//	_myExpression _myExpr(ref, alpha);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Matrix-Scalar Substract to
//template <typename T> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator-=(const reel& alpha)
//{
//	typedef Expressions<SubstractAssign, T, reel > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child();
//	_myExpression _myExpr(ref, alpha);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! 1D Accessor
//template <typename T> INLINE reel& Matrix_Base<T>::operator[](const int& idx)
//{
//	assert((idx>=0)&&(idx<SIZE));
//	return Tab[idx];
//}
////! 1D Read-Only Accessor
//template <typename T> INLINE const reel& Matrix_Base<T>::operator[](const int& idx)const
//{
//	assert((idx>=0)&&(idx<SIZE));
//	return Tab[idx];
//}
////! 2D Accessor
//template <typename T> INLINE reel& Matrix_Base<T>::operator()(const int& idxm,const int& idxn)
//{
//	assert((idxm>=0)&&(idxm<T::ROW)&&(idxn>=0)&&(idxn<T::COL));
//	return Child()(idxm,idxn);
//}
////! 2D Read-Only Accessor
//template <typename T> INLINE const reel& Matrix_Base<T>::operator()(const int& idxm,const int& idxn)const
//{
//	assert((idxm>=0)&&(idxm<T::ROW)&&(idxn>=0)&&(idxn<T::COL));
//	return Child()(idxm,idxn);
//}
////! Matrix Set
//template <typename T> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::set(const reel& value)
//{
//	typedef Expressions<Assign,T, reel> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child(); 
//	_myExpression _myExpr(ref,value);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Norm (L2)
//template <typename T> INLINE reel Matrix_Base<T>::norm()const
//{
//	return ::sqrt(norm2());
//}
////! Norm (L2)
//template <typename T> INLINE reel Matrix_Base<T>::norm2()const
//{
//	//TOD: Verifier si copy ?
//	return dot(*this);
//}
////! Norm (L1)
//template <typename T> INLINE reel Matrix_Base<T>::normL1()const
//{
//	//TOD: Verifier si copy ?
//	const typename Matrix_Base<T>::self& ref = Child();
//	reel res(0);
//	for (int i=0;i<T::ROW;i++)
//		for (int j=0;j<T::COL;j++)
//			res+=std::abs(ref(i,j));
//	return res;
//}
////! Norm (Linf)
//template <typename T> INLINE reel Matrix_Base<T>::normLinf()const
//{
//	//TOD: Verifier si copy ?
//	const typename Matrix_Base<T>::self& ref = Child();
//	reel res(::abs(ref[0]));
//	for (int i=1;i<T::SIZE;i++)
//		res = ::abs(ref[i]) > res ? ::abs(ref[i]) : res;
//	return res;
//}
////! Norm (L2)
//template <typename T> INLINE reel Matrix_Base<T>::normL2()const
//{
//	return norm();
//}
////! Matrix-Matrix Inner Product or Vector-Vector Inner Product
//template <typename T> template <typename TT> INLINE reel Matrix_Base<T>::dot(const Matrix_Base<TT>& Two)const
//{
//	typedef Matrix_Additive_Scheme_Trait< T , TT > Trait;
//	STATIC_ASSERT_INFO(T , TT , Trait::Could_Add);
//	return scalar_product_Unrolled<T::ROW>::template Operation<T,TT>::compute(Child(),Two.Child());
//}
////! Matrix-Matrix Product or Matrix-Vector Product
//template <typename T> template <typename TT> INLINE typename Matrix_Product_Scheme_Trait< T, TT >::result_type Matrix_Base<T>::operator*(const Matrix_Base<TT>& M1) const {
//	typedef Matrix_Product_Scheme_Trait< T, TT > Trait;
//	STATIC_ASSERT_INFO(T , TT , Trait::Could_Multiply);
//	typedef typename Trait::Product Matrix_Product;
//	return Matrix_Product::compute(Child(),M1.Child());
//}
////! Element-Element Product
//template <typename T> template <typename TT> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::mult(const TT& Two) {
//	typedef Expressions<MultAssign,T, TT> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child(); 
//	_myExpression _myExpr(ref, Two);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Element-Element Quotient
//template <typename T> template <typename TT> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::div(const TT& Two) {
//	typedef Expressions<DivAssign,T, TT> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child(); 
//	_myExpression _myExpr(ref, Two);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Element Sqrt
//template <typename T> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::sqrt()
//{
//	typedef Expressions<SqrtAssign,T, T> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child(); 
//	_myExpression _myExpr(ref, ref);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Matrix-Matrix Egality Check
//template <typename T> template <typename TT> INLINE bool Matrix_Base<T>::operator==(const Matrix_Base<TT>& Two) const {
//	//TOD: Verifier si copy ?
//	const typename Matrix_Base<T>::self& ref = Child();
//	bool res=true;
//	for (int i=0;(i<T::ROW)&&(res);i++)
//		for (int j=0;(j<T::COL)&&(res);j++)
//			res=(ref(i,j)==Two(i,j));
//	return res;
//}
////! Matrix-Matrix Add
//template <typename T> template <typename TT> INLINE Expressions<Add, T, TT> Matrix_Base<T>::operator+(const TT& Two) const {
//	typedef Expressions<Add, T, TT > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	return _myExpression(Child(), Two);
//}
////! Matrix-Matrix Substract
//template <typename T> template <typename TT> INLINE Expressions<Substract, T, TT> Matrix_Base<T>::operator-(const TT& Two) const {
//	typedef Expressions<Substract, T, TT > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	return _myExpression(Child(), Two);
//}
//////! Matrix-Matrix Add to
////template <typename T> template <typename TT> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator+=(const Matrix_Base<TT>& Two) {
////	typedef Expressions<AddAssign, T, Matrix_Base<TT> > _myExpression;
////	STATIC_ASSERT(_myExpression::OK);
////	typename Matrix_Base<T>::self& ref=Child();
////	_myExpression _myExpr(ref, Two);
////	Action<_myExpression>::act(_myExpr);
////	return ref;
////}
//////! Matrix-Matrix Substract to
////template <typename T> template <typename TT> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator-=(const Matrix_Base<TT>& Two) {
////	typedef Expressions<SubstractAssign,T ,TT> _myExpression;
////	STATIC_ASSERT(_myExpression::OK);
////	typename Matrix_Base<T>::self& ref=Child(); 
////	_myExpression _myExpr(ref, Two.Child());
////	Action<_myExpression>::act(_myExpr);
////	return ref;
////}
////! Matrix-Matrix Add to
//template <typename T> template <typename TT> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator+=(const TT& Expr) {
//	//typedef Matrix_Convert_Trait< T , TT > Trait;
//	//STATIC_ASSERT(Trait::Could_Convert);
//	typedef Expressions<AddAssign, T, TT> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child();
//	_myExpression _myExpr(ref,Expr);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Matrix-Matrix Substract to
//template <typename T> template <typename TT> INLINE typename Matrix_Base<T>::self& Matrix_Base<T>::operator-=(const TT& Expr) {
//	//typedef Matrix_Convert_Trait< T , TT > Trait;
//	//STATIC_ASSERT(Trait::Could_Convert);
//	typedef Expressions<SubstractAssign,T ,TT> _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	typename Matrix_Base<T>::self& ref=Child(); 
//	_myExpression _myExpr(ref,Expr);
//	Action<_myExpression>::act(_myExpr);
//	return ref;
//}
////! Write to a file
//template <typename T> INLINE void Matrix_Base<T>::write(std::ostream& f) const {
//	f.write((const char*) Tab,SIZE*sizeof(reel));
//}
////! Read from a file
//template <typename T> INLINE void Matrix_Base<T>::read(std::istream& f) {
//	f.read((char*) Tab,SIZE*sizeof(reel));
//}
////! Element-Element Product
//template <typename T1,typename T2> INLINE Expressions<Mult, T1, T2> mult(const T1 &M1,const T2 &M2)
//{
//	typedef Expressions<Mult, T1, T2> _myExpression;
//	STATIC_ASSERT( _myExpression::OK );
//	return _myExpression(M1, M2);
//}
////! Element-Element Quotient
//template <typename T1,typename T2> INLINE Expressions<Div, T1, T2> div(const T1 &M1,const T2 &M2) 
//{
//	typedef Expressions<Div, T1, T2> _myExpression;
//	STATIC_ASSERT( _myExpression::OK );
//	return _myExpression(M1, M2);
//}
////! Element Sqrt
//template <typename T> INLINE Expressions<UnarySqrt, T, void > sqrt(const Matrix_Base<T> &M1) 
//{
//	typedef Expressions<UnarySqrt, T, void > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	return _myExpression(M1.Child());
//}
////! Scalar-Matrix Add
//template <typename T> INLINE Expressions<Add, reel, T > operator+(const reel& value,const Matrix_Base<T>& M1) {
//	typedef Expressions<Add, reel, T > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	return _myExpression(value, M1.Child());
//}
////! Scalar-Matrix Substract
//template <typename T> INLINE Expressions<Substract, reel, T > operator-(const reel& value,const Matrix_Base<T>& M1) {
//	typedef Expressions<Substract, reel, T > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	return _myExpression(value, M1.Child());
//}
////! Scalar-Matrix Product
//template <typename T> INLINE Expressions<Mult, reel, T > operator*(const reel& value,const Matrix_Base<T>& M1) {
//	typedef Expressions<Mult, reel, T > _myExpression;
//	STATIC_ASSERT(_myExpression::OK);
//	return _myExpression(value, M1.Child());
//}

NAMESPACE_END

#endif
